import os from 'os'
import fs, { WriteStream } from 'fs';
import * as sinon from 'sinon';
import {expect} from 'chai'
import axios from "axios";
import {download, requestURL} from '../../src/tool/download'
import logging from '../../src/logging'

describe('download function', () => {
    let tmpDirStub: sinon.SinonStub;
    let mkdirSyncStub: sinon.SinonStub;
    let writeFileSyncStub: sinon.SinonStub;
    let axiosRequestStub: sinon.SinonStub;
    let fsCreateWriteStreamStub: sinon.SinonStub;
    let responseDataPipeStub: sinon.SinonStub;
    let responseDataOnStub: sinon.SinonStub;
    let loggingInfoStub: sinon.SinonStub;

    beforeEach(() => {
        loggingInfoStub = sinon.stub(logging, 'info');
        mkdirSyncStub = sinon.stub(fs, 'mkdirSync');
        writeFileSyncStub = sinon.stub(fs, 'writeFileSync');
        tmpDirStub = sinon.stub(os, 'tmpdir').returns("/tmp")
        responseDataPipeStub = sinon.stub()
        responseDataOnStub = sinon.stub().callsFake((event, cb) => {
            if (event === 'close') {
                cb();
            }
        });
        const response = {
            data: {
                pipe: responseDataPipeStub,
                on: responseDataOnStub,
            },
            status: 200,
        };
        axiosRequestStub = sinon.stub(axios, 'request');
        axiosRequestStub.resolves(response);
        fsCreateWriteStreamStub = sinon.stub(fs, 'createWriteStream').returns({
            // @ts-ignore
            on: function (event: "finish", listener: () => void): WriteStream {
                listener()
                return this
            }
        });
    });

    afterEach(() => {
        sinon.restore();
    });

    const toolUrl = "https://flow-tool-registry.com/tool-registry/jdk/jdk-19.0.1-darwin-x64.tar.gz";
    it('should invoke os.tmpdir() when headers and destDir both undefined', async () => {
        const destDir: string = await download(toolUrl)
        expect(destDir).to.contains("/tmp")

        sinon.assert.calledOnce(tmpDirStub)
        sinon.assert.calledOnce(mkdirSyncStub)
        sinon.assert.calledOnce(writeFileSyncStub)
        sinon.assert.calledOnceWithMatch(axiosRequestStub, {
            method: 'GET',
            url: toolUrl,
            headers: new axios.AxiosHeaders(),
            responseType: 'stream',
        })
        sinon.assert.calledOnce(fsCreateWriteStreamStub)
    });

    it('should not invoke os.tmpdir(), pass headers to axiosHeaders when headers not undefined and destDir is /tmp/test', async () => {
        const headers = {
            'Accept': 'application/octet-stream',
        }

        const axiosHeaders = new axios.AxiosHeaders()
        axiosHeaders.set("Accept", "application/octet-stream")

        const destDir: string = await download(toolUrl, headers, "/tmp/test")
        expect(destDir).to.contains("/tmp/test")

        sinon.assert.notCalled(tmpDirStub)
        sinon.assert.calledOnce(mkdirSyncStub)
        sinon.assert.calledOnce(writeFileSyncStub)
        sinon.assert.calledOnceWithMatch(axiosRequestStub, {
            method: 'GET',
            url: toolUrl,
            headers: axiosHeaders,
            responseType: 'stream',
        })
        sinon.assert.calledOnce(fsCreateWriteStreamStub)
    })

    it('download real file', async () => {
        const toolUrl = "https://agent-install-cn-beijing.oss-cn-beijing.aliyuncs.com/install_linux.sh";
        const destDir: string = await download(toolUrl, undefined, "/tmp/test")
        console.log(`Download ${destDir} successfully`)
        expect(destDir).to.contains("/tmp/test")
    })

    it('try to get tool-registry sidecar but ECONNREFUSED', async () => {
        const cpToolUrl = "http://localhost:11516/restore?toolname=jdk&version=19.0.1&arch=x64";
        try {
            const result: string = await requestURL(cpToolUrl, 5000)
            console.log(`Get result: ${result}`)
            expect(false).to.be.true
        } catch (e) {
            console.log(`Get error: ${e}`)
            expect(e).to.contains("ECONNREFUSED")
        }
    })
})